package com.pug.security.config;

import com.pug.security.config.security.handler.MyAccessDeniedHandler;
import com.pug.security.config.security.handler.MyAuthenticationSuccessHandler;
import com.pug.security.config.security.handler.MyAuthenticationFailureHandler;
import com.pug.security.service.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailService userDetailService;


    // 认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        String newpassword = passwordEncoder().encode("123456");
        auth.inMemoryAuthentication()
                .withUser("admin").password(newpassword).roles("Admin")
                // 下一个配置
                .and()
                .withUser("yykk").password(newpassword).roles("User");

        // 基于接口userDetailsService的认证
        auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder());
    }

    // 授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // 所有的请求开始接受认证
                .authorizeRequests()
                // 匹配到这些路径是不需要认证的
                .antMatchers("/toLogin", "/index", "/myerror","/nopermission").permitAll()

                // 配置角色的访问权限 ---- (注意：拼ROLE_的问题)
                .antMatchers("/user/get/**").hasRole("User")
                .antMatchers("/user/**").hasRole("Admin")

                // 匹配不到的，剩下的，全部进行认证
                .anyRequest().authenticated()
                // 下一个配置
                .and()
                // 提交表单
                .formLogin()
                // 自定义登陆页面
                .loginPage("/toLogin")
                // 给form表单的action进行赋值，默认是/login
                .loginProcessingUrl("/login")
                // 给form表单的input输入框的name赋值
                .usernameParameter("username")
                .passwordParameter("password")
                // 登陆成功之后处理 -- 自定义登录成功的处理器
                .successHandler(new MyAuthenticationSuccessHandler("/index"))
                // 登陆失败的处理 -- 自定义登录失败的处理器
                .failureHandler(new MyAuthenticationFailureHandler("/myerror"))
                // 设置记住密码
                .and()
                .rememberMe()
                .rememberMeParameter("remember-me")
                .rememberMeCookieName("ksd-remember-me")
                .tokenValiditySeconds(1800)
                .and()
                // 如果出现权限不足，进入到403 -- 自定义403处理器
                .exceptionHandling()
                .accessDeniedHandler(new MyAccessDeniedHandler())
                // 下一个配置
                .and()
                // 关闭csrf跨站访问的防护
                .csrf().disable();
    }


    // 放行配置
    // 写在这里的资源放行是不会进入到过滤器链的。
    @Override
    public void configure(WebSecurity webSecurity) throws Exception {
        webSecurity.ignoring().antMatchers("/index",
                "/js/**", "/css/**", "/fonts/**", "/images/**", "/img/**");
    }


    // 注册一个加密器
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

//    public static void main(String[] args) {
//        System.out.println(new BCryptPasswordEncoder().encode("123456"));
//    }

}
